#include "stddef.h"
#include "string.h"
#include "cpuid.h"

int memcmp_sse4_1(const uint8_t * const m1, const uint8_t * const m2, const size_t count)
{
	size_t i, FLAG;

	i = 0;

	/* align "m1" on a SSE_XMM_SIZE boundary */
	while((((size_t)m1 + i) & (SSE_XMM_SIZE-1)))
	{
		if(m1[i] != m2[i])
		{
			if(m1[i] > m2[i]){ return 1; }
			else{ return -1; }
		}
		i++;
	}

	/* check to see if "m2" is aligned on a SSE_XMM_SIZE boundary */
	if(!(((size_t)m2 + i) & (SSE_XMM_SIZE-1)))
	{
		for(; i + 64 < count; i += 64)
		{
			/* this will evaluate 64 bytes at a time using non-temporal stores */
			asm(" movntdqa 0(%1), %%xmm0;  movntdqa 0(%2), %%xmm1;	"
				" movntdqa 16(%1), %%xmm2; movntdqa 16(%2), %%xmm3;	"
				" movntdqa 32(%1), %%xmm4; movntdqa 32(%2), %%xmm5;	"
				" movntdqa 48(%1), %%xmm6; movntdqa 48(%2), %%xmm7;	"
				" ptest %%xmm0, %%xmm1; "
				" jnc .ptest_failed0;	"
				" ptest %%xmm2, %%xmm3;	"
				" jnc .ptest_failed0;    "
				" ptest %%xmm4, %%xmm5;	"
				" jnc .ptest_failed0;    "
				" ptest %%xmm6, %%xmm7;	"
				" jnc .ptest_failed0;    "
				" mov $0, %0;			"
				" jmp .ptest_done0;		"
				".ptest_failed0:;		"
				" mov $1, %0;			"
				".ptest_done0:;			"
				:"=r"(FLAG):"r"((size_t)m1),"r"((size_t)m2));

			/* ToDo: figure out how to test for greater-than and less-than outcomes */
			if(FLAG){ return 1; }
		}
	}
	/* if "m2" is not aligned, we need to use MOVDQU as the load instruction */
	else
	{
		for(; i + 64 < count; i += 64)
		{
			/* this will evaluate 64 bytes at a time with non-temporal "m1" loading */
			asm(" movntdqa 0(%1), %%xmm0;  movdqu 0(%2), %%xmm1;	"
				" movntdqa 16(%1), %%xmm2; movdqu 16(%2), %%xmm3;	"
				" movntdqa 32(%1), %%xmm4; movdqu 32(%2), %%xmm5;	"
				" movntdqa 48(%1), %%xmm6; movdqu 48(%2), %%xmm7;	"
				" ptest %%xmm0, %%xmm1; "
				" jnc .ptest_failed1;	"
				" ptest %%xmm2, %%xmm3;	"
				" jnc .ptest_failed1;    "
				" ptest %%xmm4, %%xmm5;	"
				" jnc .ptest_failed1;    "
				" ptest %%xmm6, %%xmm7;	"
				" jnc .ptest_failed1;    "
				" mov $0, %0;			"
				" jmp .ptest_done1;		"
				".ptest_failed1:;		"
				" mov $1, %0;			"
				".ptest_done1:;			"
				:"=r"(FLAG):"r"((size_t)m1),"r"((size_t)m2));

			/* ToDo: figure out how to test for greater-than and less-than outcomes */
			if(FLAG){ return 1; }
		}
	}

	return memcmp(m1 + i, m2 + i, count - i);
}

int memcmp_std(const uint8_t * const m1, const uint8_t * const m2, const size_t count)
{
	size_t i;

	for(i = 0; i < count; i++)
	{
		if(m1[i] != m2[i])
		{ 
			if(m1[i] > m2[i]){ return 1; }
			else{ return -1; }
		}
	}

	return 0;
}


